package com.oglvip.business.remote.support.proxy.exchange;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.oglvip.business.remote.support.exception.RestException;
import com.oglvip.business.remote.support.proxy.ProxyFactory;
import com.oglvip.business.remote.support.request.RequestEntity;
import com.oglvip.business.remote.support.utils.MethodUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
 * @auther hanchao
 * @date 2016/12/3 17:50
 */
public class HttpClientExchanger implements Exchanger {
    private static final Logger logger = LoggerFactory.getLogger(HttpClientExchanger.class);
    private ObjectMapper mapper;
    private HttpClient httpClient;

    public void setMapper(ObjectMapper mapper) {
        this.mapper = mapper;
    }

    public void setHttpClient(HttpClient httpClient) {
        this.httpClient = httpClient;
    }

    protected ObjectMapper getMapper() {
        if(this.mapper == null){
            mapper = new ObjectMapper();
        }
        return mapper;
    }

    protected HttpClient getHttpClient() {
        if(httpClient == null){
            return HttpClients.createDefault();
        }
        return httpClient;
    }

    @Override
    public Object request(RequestEntity requestEntity, Method method) throws Throwable {
        //HttpUriRequest httpRequest
        Object result;
        HttpUriRequest httpUriRequest = buildRequest(requestEntity);
        HttpResponse response = getHttpClient().execute(httpUriRequest);
        if(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK){
            if(method.getGenericReturnType() instanceof ParameterizedType){
                TypeReference reference = (TypeReference) ProxyFactory.getJacksonSpringRefrence(MethodUtils.getGenericReturnTypeName(method));
                if(reference == null){
                    throw new RestException("cant get generic reference from proxy factory!");
                }
                result = getMapper().readValue(response.getEntity().getContent(),reference);
            }else{
                result = getMapper().readValue(response.getEntity().getContent(),method.getReturnType());
            }
            return result;
        }else{
            logger.error("server error,responsed :\n{}",EntityUtils.toString(response.getEntity()));
            throw new RestException("server error,responsed status "+response.getStatusLine().getStatusCode());
        }
    }

    protected HttpUriRequest buildRequest(RequestEntity requestEntity) throws UnsupportedEncodingException, JsonProcessingException {
        HttpUriRequest request;
        switch (requestEntity.getHttpMethod()){
            case RequestEntity.GET:
                request = new HttpGet(requestEntity.toUrl());
                break;
            case RequestEntity.POST:
                request = new HttpPost(requestEntity.toUrl());
                if(requestEntity.getFormParams() != null && !requestEntity.getFormParams().isEmpty()){
                    Map<String, Object> formParams = requestEntity.getFormParams();
                    ((HttpPost)request).setEntity(new UrlEncodedFormEntity(buildParams(formParams),"UTF-8"));
                }else if(requestEntity.getBody() != null){
                    String body = getMapper().writeValueAsString(requestEntity.getBody());
                    ((HttpPost)request).setEntity(new StringEntity(body));
                }
                break;
            case RequestEntity.PUT:
                request = new HttpPut(requestEntity.toUrl());
                if(requestEntity.getBody() != null){
                    String body = getMapper().writeValueAsString(requestEntity.getBody());
                    ((HttpPut)request).setEntity(new StringEntity(body));
                }
                break;
            case RequestEntity.DELETE:
                request = new HttpDelete(requestEntity.toUrl());
                break;
            default:
                request = new HttpGet(requestEntity.toUrl());
                break;
        }
        request.addHeader(HttpHeaders.CONTENT_TYPE,requestEntity.getContentType());
        request.addHeader(HttpHeaders.ACCEPT,requestEntity.getAccept());

        return request;
    }

    static List buildParams(Map params){
        List <NameValuePair> nvps = new ArrayList<NameValuePair>();
        Iterator it=params.keySet().iterator();
        while(it.hasNext()){
            String key=(String)it.next();
            Object v=params.get(key);
            if(v != null){
                nvps.add(new BasicNameValuePair(key, String.valueOf(v)));
            }
        }
        nvps.add(new BasicNameValuePair("icForm.isHistory", "13"));
        nvps.add(new BasicNameValuePair("icForm.isHistory", "0"));
        nvps.add(new BasicNameValuePair("icForm.isHistory", "11"));
        nvps.add(new BasicNameValuePair("icForm.isHistory", "3"));
        return nvps;
    }

}
